﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LxCFD
{
    public static class MultiThreads
    {
        private volatile static int _TaskCount = 1;
        private volatile static int _FinishedCount = 0;
        public static readonly object GlobalLock = new object();
        private static Task[] _CalTasks;
        private volatile static bool _is1or2;
        private volatile static bool _isCalTaskRunning = false;
        private static ManualResetEventSlim _CalTasksResetEvent_1 = new ManualResetEventSlim(false);
        private static ManualResetEventSlim _CalTasksResetEvent_2 = new ManualResetEventSlim(false);
        public static int GetThreadsCount()
        {
            return _TaskCount;
        }
        public static void SetThreadsCount(int count)
        {
            if (ComputeState.GetIsRunning())
            {
                LxConsole.Warn("正在计算中，不可更改线程数");
                return;
            }
            if (count <= 0)
            {
                LxConsole.Warn("线程数不可设置小于1,已更正为1");
                _TaskCount = 1;
            }
            else
            {
                _TaskCount = count;
            }
        }
        public static void RunHostTask(Action hostAction)
        {
            if (!ComputeState.SetIsRunning(true))
            {
                LxConsole.Warn("正在计算中");
                return;
            }
            Task.Run(() =>
            {
                _CalTasks = new Task[_TaskCount];
                hostAction.Invoke();
                _CalTasks = null;
                ComputeState.SetIsRunning(false);
            });
        }

        public static void RunCalTasks(Action<int> calAction)
        {
            if (_isCalTaskRunning)
            {
                throw new Exception();
            }
            else
            {
                _isCalTaskRunning = true;
                for (int i1 = 0; i1 < _TaskCount; i1++)
                {
                    int k = i1;
                    _CalTasks[k] = Task.Run(() => { calAction.Invoke(k); });
                }
                Task.WaitAll(_CalTasks);
                _isCalTaskRunning = false;
            }
        }
        public static void Sync(int taskIndex)
        {
            Sync(taskIndex, () => { });
        }
        public static void Sync(int taskIndex, Action runOnce)
        {
            if (Interlocked.Increment(ref _FinishedCount) == _TaskCount)
            {
                _FinishedCount = 0;
                runOnce();
                if (_is1or2)
                {
                    _is1or2 = !_is1or2;
                    _CalTasksResetEvent_2.Reset();
                    _CalTasksResetEvent_1.Set();
                }
                else
                {
                    _is1or2 = !_is1or2;
                    _CalTasksResetEvent_1.Reset();
                    _CalTasksResetEvent_2.Set();
                }
            }
            else
            {
                if (_is1or2)
                {
                    _CalTasksResetEvent_1.Wait();
                }
                else
                {
                    _CalTasksResetEvent_2.Wait();
                }
            }
        }
    }
}